;------------Loader--------------
%include "boot.inc"
section loader vstart=LOADER_BASE_ADDR		;section.loader.start get the real offset addr base on file top
LOADER_STACK_TOP equ LOADER_BASE_ADDR		;define stack addr
;---------Built GDT table in memory--------
GDT_BASE:		dd	0x00000000
			dd	0x00000000
CODE_DESC:		dd	0x0000FFFF
			dd	DESC_CODE_HIGH4
DATA_STACK_DESC:	dd	0x0000FFFF
        		dd	DESC_DATA_HIGH4
VIDEO_DESC:		dd	0x80000007
			dd	DESC_VIDEO_HIGH4  ;Base addr:0x000b8000  limit=(0xbffff-0xb8000)/4k=0x7fff/0x1000=0x7

GDT_SIZE 		equ	$-GDT_BASE	;  $ is mean first addr after DGT table, GDT start with 0
GDT_LIMIT		equ	GDT_SIZE - 1

times 60 dq 0	;save 60 slots for GDT item

;--------Create selectors for compiler-------
SELECTOR_CODE	equ	(0x0001 << 3) + TI_GDT + RPL0
SELECTOR_DATA	equ 	(0x0002 << 3) + TI_GDT + RPL0
SELECTOR_VIDEO	equ 	(0x0003 << 3) + TI_GDT + RPL0

;-------------restore total memory-----------
total_mem_bytes: dd 0	;0xb00  

;--------Create GDT table pointer------------
gdt_ptr:    dw GDT_LIMIT
            dd GDT_BASE

ards_buf:	times 244 db 0
ards_nr:	dw 0		;record number of ards struct

;-------------loader start--------------------
loader_start:
;int 0x15 eax=0x0000e820  get the layout of memory
xor ebx,ebx
mov edx,0x534d4150
mov di,ards_buf
.e820_mem_get_loop:
mov eax,0x0000e820
mov ecx,20
int 0x15
jc .e820_failed_so_try_e801    ;if cf=1 jump to e801 function, try to get mem size
add di,cx
inc word [ards_nr]
cmp ebx,0
jnz .e820_mem_get_loop

;find the max(BaseAddrLow + LengthLow) value, it's the memory size
mov cx,[ards_nr]	;get count of ards
mov ebx,ards_buf	;base addr
xor edx,edx		;keep the value of mem size
.find_max_mem_area:
mov eax,[ebx]		;BaseAddrLow
add eax,[ebx+8]		;LengthLow
add ebx,20
cmp edx,eax 
jge .next_ards
mov edx,eax
.next_ards:
loop .find_max_mem_area
jmp .mem_get_ok

;int 0x15 eax=0x0000e801 
.e820_failed_so_try_e801:
mov eax,0xe801
int 0x15
jc .e801_failed_so_try_88

mov cx,0x400	;1kb = 0x400
mul cx		;16bit mul  high 16bit keep in dx, low 16bit keep in ax
shl edx,16
and eax,0x0000FFFF
or edx,eax
add edx,0x100000    ;1MB=0x100000
mov esi,edx	    ;backup edx

xor eax,eax
mov ax,bx
mov ecx,0x10000     ;64kb=0x10000
mul ecx             ;32bit mul  high 32bit keep in edx, low 32bit keep in eax, now edx must be zero 
add esi,eax
mov edx,esi
jmp .mem_get_ok

;int 0x15 ah=0x88
.e801_failed_so_try_88:
mov ah,0x88
int 0x15
jc .error_hlt
and eax,0x0000FFFF        ;ax keep num

mov cx,0x400    	  ;1kb=0x400
mul cx
shl edx,16
and eax,0x0000FFFF
or edx,eax
add edx,0x100000

.mem_get_ok:
mov [total_mem_bytes],edx

;-----------protection model------------------
;setp 1 open A20
in al,0x92
or al,0000_0010B
out 0x92,al

;setp 2 load GDTR
lgdt [gdt_ptr]

;setp 3 set cr0
mov eax,cr0
or eax, 0x00000001
mov cr0,eax

jmp SELECTOR_CODE:p_mode_start		;reflash working flow and set cs SELECTOR_CODE

.error_hlt:
hlt

[bits 32]
p_mode_start:
mov ax,SELECTOR_DATA
mov ds,ax
mov es,ax
mov fs,ax
mov ss,ax
mov esp,LOADER_STACK_TOP
mov ax,SELECTOR_VIDEO
mov gs,ax

;-----------------load kernel.bin------------
mov eax,KERNEL_START_SECTOR
mov ebx,KERNEL_BIN_BASE_ADDR
mov ecx,200

call rd_disk_m_32

call setup_page				;Create the PDE table and PTE table

sgdt [gdt_ptr]				;restore the gdt addr

add dword [gdt_ptr+2],0xc0000000	;move GDT table virtul addr to kenerl menary   0xc0000900

mov ebx,[gdt_ptr+2]			;move video segment virtul addr to kenerl memary  0xc000b800
or dword [ebx+24+4],0xc0000000

add esp,0xc0000000			;move stack virtul addr to kenerl memary  0xc0000900

mov eax,PAGE_DIR_TABLE_POS
mov cr3,eax

;set cr0 pg
mov eax,cr0
or eax,0x80000000
mov cr0,eax

;use the virtul addr to load GDT table  
lgdt [gdt_ptr]

jmp SELECTOR_CODE:enter_kernel
enter_kernel:

call kernel_init
mov esp,0xc009f000
jmp KERNEL_ENTRY_POINT

;-----------------kernel init----------------------
kernel_init:
xor eax,eax
xor ebx,ebx		;keep the pos of program header table
xor ecx,ecx		;keep the num of program header
xor edx,edx		;keep size of program header

mov dx,[KERNEL_BIN_BASE_ADDR + 42]	;e_phentsize 
mov ebx,[KERNEL_BIN_BASE_ADDR + 28]	;e_phoff
add ebx,KERNEL_BIN_BASE_ADDR		;get real addr of program header table
mov cx,[KERNEL_BIN_BASE_ADDR + 44]	;e_phnum

.each_segment:
cmp byte [ebx + 0],PT_NULL
je .PTNULL

push dword [ebx + 16]		;p_filesz
mov eax,[ebx + 4]		;p_offset
add eax,KERNEL_BIN_BASE_ADDR	;get real addr of program header
push eax			;source addr
push dword [ebx + 8]		;p_vaddr destination addr
call mem_cpy
add esp,12			;clear stack

.PTNULL:
add ebx,edx
loop .each_segment
ret

;--------------memcpy--------------
mem_cpy:
cld
push ebp
mov ebp,esp
push ecx
mov edi,[ebp + 8]	;dst
mov esi,[ebp + 12]	;src
mov ecx,[ebp + 16]	;size
rep movsb

;restore context
pop ecx
pop ebp
ret

;----------Create PDE table and PTE table-----------
setup_page:
;clear the memary of PDE table
mov ecx,4096   ;4kb  PDE start addr is 0x00100000=1MB
mov esi,0
.clear_page_dir:
mov byte [PAGE_DIR_TABLE_POS + esi],0
inc esi
loop .clear_page_dir

;Create PDE
mov eax,PAGE_DIR_TABLE_POS
add eax,0x1000
mov ebx,eax

or eax,PG_US_U | PG_RW_W | PG_P
mov [PAGE_DIR_TABLE_POS + 0x0],eax
mov [PAGE_DIR_TABLE_POS + 0xc00],eax

sub eax,0x1000
mov [PAGE_DIR_TABLE_POS + 4092],eax

;Create PTE table
mov ecx,256				;map 1mb memary
mov esi,0
mov edx,PG_US_U | PG_RW_W | PG_P	;edx=111B 
.create_pte:
mov [ebx+esi*4],edx			;ebx=0x101000
add edx,4096  				;add edx 1kb
inc esi					
loop .create_pte

;Create kernel other PDE
mov eax,PAGE_DIR_TABLE_POS
add eax,0x2000				;point to second PTE postion
or eax,PG_US_U | PG_RW_W | PG_P
mov ebx,PAGE_DIR_TABLE_POS
mov ecx,254
mov esi,769
.create_kernel_pde:
mov [ebx+esi*4],eax
add eax,0x1000
inc esi
loop .create_kernel_pde
ret


;-----------read disk---------------
rd_disk_m_32:

;backup eax cx
mov esi,eax
mov di,cx

;step 1 set sector number
mov dx,0x1f2
mov al,cl
out dx,al

mov eax,esi			;restore eax

;step 2 set LBA addr
mov dx,0x1f3
out dx,al

mov cl,8
shr eax,cl
mov dx,0x1f4
out dx,al

shr eax,cl
mov dx,0x1f5
out dx,al

shr eax,cl
and al,0x0f
or al,0xe0
mov dx,0x1f6
out dx,al

;step 3 send commend
mov dx,0x1f7
mov al,0x20
out dx,al

.not_ready:
nop
in al,dx
and al,0x88
cmp al,0x08
jnz .not_ready

mov ax,di
mov dx,256
mul dx
mov cx,ax
mov dx,0x1f0
.go_on_read:
in ax,dx
mov [ebx],ax
add ebx,2
loop .go_on_read
ret






































































